#include "gkt_defines.h"
#include "gkt_debug.h"
#include "gkt_window.h"

static const gkt_widget_event_handler sc_widget_event_handlers[GKT_WIDGET_TYPE_MAX] = {
#if defined(GKT_CONFIG_SCREEN_ENABLE) && GKT_CONFIG_SCREEN_ENABLE
	[GKT_WIDGET_TYPE_LABEL] = gkt_widget_label_event_handler,
	[GKT_WIDGET_TYPE_IMAGE] = gkt_widget_image_event_handler,
	[GKT_WIDGET_TYPE_SELECT] = gkt_widget_select_event_handler,
#endif
	[GKT_WIDGET_TYPE_INPUTBOX] = gkt_widget_inputbox_event_handler,
	[GKT_WIDGET_TYPE_LIST] = gkt_widget_list_event_handler,
};

int gkt_widget_event_dispatch(gkt_widget_s *widget, 
				uint32_t major_type, uint32_t minor_type, 
				uint32_t data)
{
	gkt_widget_event_handler event_handler;

	if (__LIKELY(widget->desc->type < GKT_WIDGET_TYPE_MAX))	{
		event_handler = sc_widget_event_handlers[widget->desc->type];
		return (*event_handler)(widget, major_type, minor_type, data);
	}

	gkt_error("widget_event_dispatch: type(%u) not support!\n", 
			widget->desc->type);

	return GKT_ENOTSUPPORT;
}

gkt_widget_s *gkt_widget_by_id(gkt_widget_id_t widget_id)
{
	gkt_window_s *window;
	gkt_widget_s *widget;

	window = gkt_window_find(GKT_WINDOW_ID_CURRENT);
	if (__LIKELY(window && (widget_id < window->desc->widget_nums)))
		widget = &window->widgets[widget_id];
	else
		widget = NULL;

	return widget;
}

void gkt_widget_set_showable_by_id(gkt_widget_id_t widget_id, 
			int showable)
{
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);
	if (__LIKELY(widget)) {
		if (showable)
			widget->flags |= GKT_WIDGET_F_SHOWABLE;
		else
			widget->flags &= ~GKT_WIDGET_F_SHOWABLE;
	}
}

void gkt_widget_update(gkt_widget_s *widget)
{
	if (widget->flags & GKT_WIDGET_F_SHOW) {
		gkt_widget_event_dispatch(widget, 
				GKT_EVENT_WIDGET, GKT_WIDGET_EVENT_SHOW, 
				1);
	}
}
void gkt_widget_update_by_id(gkt_widget_id_t widget_id)
{
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);
	if (__LIKELY(widget))
		gkt_widget_update(widget);
}

void gkt_widget_show(gkt_widget_s *widget, uint32_t update)
{
	int retval;

	widget->flags |= GKT_WIDGET_F_SHOW;
	retval = gkt_widget_event_dispatch(widget, 
					GKT_EVENT_WIDGET, GKT_WIDGET_EVENT_SHOW, 
					update);
	if (__UNLIKELY(retval != GKT_SUCCESS))
		widget->flags &= ~GKT_WIDGET_F_SHOW;
}
void gkt_widget_show_by_id(gkt_widget_id_t widget_id)
{
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);

	if (__LIKELY(widget) 
		&& (widget->window->flags & GKT_WINDOW_F_SHOW)
		&& (widget->flags & GKT_WIDGET_F_SHOWABLE)
		&& !(widget->flags & GKT_WIDGET_F_SHOW)) 
	{
		if (widget->flags & GKT_WIDGET_F_FOCUS) {
			if (!widget->window->widget_focus)
				widget->window->widget_focus = widget;
			else if (widget->window->widget_focus != widget)
				widget->flags &= ~GKT_WIDGET_F_FOCUS;
		}

		gkt_widget_show(widget, 1);
	}
}

int gkt_widget_is_showed_by_id(gkt_widget_id_t widget_id)
{
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);

	if (__LIKELY(widget)
		&& (widget->window->flags & GKT_WINDOW_F_SHOW)
		&& (widget->flags & GKT_WIDGET_F_SHOW))
	{
		return 1;
	}

	return 0;
}

void gkt_widget_hide(gkt_widget_s *widget)
{
	gkt_window_s *window;

	if (widget->flags & GKT_WIDGET_F_SHOW) {
		widget->flags &= ~GKT_WIDGET_F_SHOW;

		window = widget->window;
		if (window->widget_focus == widget)
			window->widget_focus = NULL;

#if defined(GKT_CONFIG_SCREEN_ENABLE) && GKT_CONFIG_SCREEN_ENABLE
		gkt_widget_event_dispatch(widget, 
				GKT_EVENT_WIDGET, GKT_WIDGET_EVENT_HIDE, 
				GKT_WIDGET_PAINT_EXCUTE | GKT_WIDGET_PAINT_UPDATE);
#else
		gkt_widget_event_dispatch(widget, 
				GKT_EVENT_WIDGET, GKT_WIDGET_EVENT_HIDE, 
				0);
#endif
	}
}
void gkt_widget_hide_by_id(gkt_widget_id_t widget_id)
{
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);

	if (__LIKELY(widget)
		&& (widget->window->flags & GKT_WINDOW_F_SHOW))
	{
		gkt_widget_hide(widget);
	}
}

#if defined(GKT_CONFIG_SCREEN_ENABLE) && GKT_CONFIG_SCREEN_ENABLE
void gkt_widget_enable_item_focus_by_id(gkt_widget_id_t widget_id)
{
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);

	if (__LIKELY(widget)
		&& (widget->flags & GKT_WIDGET_F_FOCUSABLE))
	{
		widget->flags |= GKT_WIDGET_F_ITEM_FOCUS;
	}
}
#endif

void gkt_widget_set_focus_by_id(gkt_widget_id_t widget_id)
{
	gkt_window_s *window;
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);

	if (__LIKELY(widget)
		&& (widget->flags & GKT_WIDGET_F_FOCUSABLE)
		&& !(widget->flags & GKT_WIDGET_F_FOCUS)) 
	{
		window = widget->window;

		if (widget->flags & GKT_WIDGET_F_SHOW) {
			if (window->widget_focus) {
				window->widget_focus->flags &= ~GKT_WIDGET_F_FOCUS;
				if (window->widget_focus->flags & GKT_WIDGET_F_SHOW) {
					gkt_widget_event_dispatch(window->widget_focus, 
							GKT_EVENT_WIDGET, GKT_WIDGET_EVENT_LOST_FOCUS, 
							1);
				}
			}

			widget->flags |= GKT_WIDGET_F_FOCUS;
			window->widget_focus = widget;
			gkt_widget_event_dispatch(widget, 
					GKT_EVENT_WIDGET, GKT_WIDGET_EVENT_SET_FOCUS, 
					1);
		}
		else {
			if (window->widget_focus)
				window->widget_focus->flags &= ~GKT_WIDGET_F_FOCUS;
			widget->flags |= GKT_WIDGET_F_FOCUS;
			window->widget_focus = widget;
		}
	}
}

int gkt_widget_set_attr_by_id(gkt_widget_id_t widget_id, 
				uint32_t attr)
{
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);
	int retval;

	if (__LIKELY(widget)) {
		retval = gkt_widget_event_dispatch(widget, 
						GKT_EVENT_WIDGET, GKT_WIDGET_EVENT_SET_ATTR, 
						attr);
	}
	else
		retval = GKT_ENOTEXIST;

	return retval;
}

int gkt_widget_set_data_by_id(gkt_widget_id_t widget_id, 
				uint32_t data)
{
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);
	int retval;

	if (__LIKELY(widget)) {
		retval = gkt_widget_event_dispatch(widget, 
						GKT_EVENT_WIDGET, GKT_WIDGET_EVENT_SET_DATA, 
						data);
	}
	else
		retval = GKT_ENOTEXIST;

	return retval;
}

void gkt_widget_reset_by_id(gkt_widget_id_t widget_id)
{
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);

	if (__LIKELY(widget)) {
		gkt_widget_event_dispatch(widget, 
				GKT_EVENT_WIDGET, GKT_WIDGET_EVENT_RESET, 
				0);
	}
}

#if defined(GKT_CONFIG_SCREEN_ENABLE) && GKT_CONFIG_SCREEN_ENABLE \
	&& GKT_WIDGET_MULTIPLE_COLOR_ENABLE
void gkt_widget_set_color_by_id(gkt_widget_id_t widget_id, 
				gkt_color_t fg_color, gkt_color_t bg_color)
{
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);
	
	if (__LIKELY(widget)) {
		widget->fg_color = fg_color;
#if GKT_WIDGET_BGCOLOR_VARIOUS
		widget->bg_color = bg_color;
#else
		gkt_unused(bg_color);
#endif
		if (widget->flags & GKT_WIDGET_F_SHOW) {
			gkt_widget_event_dispatch(widget,
				GKT_EVENT_WIDGET, GKT_WIDGET_EVENT_SHOW,
				1);
		}
	}
}
void gkt_widget_set_fg_color_by_id(gkt_widget_id_t widget_id, 
				gkt_color_t color)
{
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);
	
	if (__LIKELY(widget)) {
		widget->fg_color = color;
		if (widget->flags & GKT_WIDGET_F_SHOW) {
			gkt_widget_event_dispatch(widget,
				GKT_EVENT_WIDGET, GKT_WIDGET_EVENT_SHOW,
				1);
		}
	}
}
void gkt_widget_set_bg_color_by_id(gkt_widget_id_t widget_id, 
				gkt_color_t color)
{
#if GKT_WIDGET_BGCOLOR_VARIOUS
	gkt_widget_s *widget = gkt_widget_by_id(widget_id);
	
	if (__LIKELY(widget)) {
		widget->bg_color = color;
		if (widget->flags & GKT_WIDGET_F_SHOW) {
			gkt_widget_event_dispatch(widget,
				GKT_EVENT_WIDGET, GKT_WIDGET_EVENT_SHOW,
				1);
		}
	}
#else
	gkt_unused(widget_id);
	gkt_unused(color);
#endif
}
#endif

